﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using SimpleMap.Binders;
using SimpleMap.ClassFactories;
using SimpleMap.DataLinks;

namespace SimpleMap
{
    public class ProjectionEnumerator<T>:IEnumerator<T>
    {


        
        public ProjectionEnumerator(IDataReader reader, List<IValueBinding<T>> elements, IClassFactory<T> factory)
        {
            if (factory == null) 
            { 
                throw new ArgumentNullException("factory"); 
            }

            if ((elements == null) || (elements.Count == 0)) 
            {
                throw new ApplicationException("Atleast one link element is required");
            }
            
            _factory = factory;
            _elements = elements;
            _projectionSet = this.ProjectionSet(reader.GetSchemaTable());
            _reader = reader;
        }
        
        #region IEnumerator<T> Members

        public T Current 
        {
               get{
                

                   T item = _factory.Create();

                foreach (ProjectionLink<T> field in _projectionSet)
                {
                    field.Setter.SetValue(item, _reader[field.Ordinal]);
                }
        

                return item;
            }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            
        }

        #endregion

        #region IEnumerator Members

        object System.Collections.IEnumerator.Current
        {
            get { return (object)this.Current; }
        }

        public bool MoveNext()
        {
            return _reader.Read();
        }

        public void Reset()
        {
            throw new NotImplementedException();
        }

        #endregion

        private List<ProjectionLink<T>> ProjectionSet(DataTable schema)
        {
            List<ProjectionLink<T>> set = new List<ProjectionLink<T>>();

            foreach (IValueBinding<T> e in _elements)
            {

                foreach (DataRow r in schema.Rows)
                {
                    if (r[NAME_COLUMN].ToString() == e.Column)
                    {
                        ProjectionLink<T> item = new ProjectionLink<T>();
                        item.Setter = e.Setter;
                        item.Ordinal = (Int32)r[ORDINAL_COLUMN];
                        set.Add(item);
                    }
                }
            }

            return set;

        }

        private IDataReader _reader = null;
        private const string NAME_COLUMN = "ColumnName";
        private const string ORDINAL_COLUMN = "ColumnOrdinal";

        List<ProjectionLink<T>> _projectionSet;
        private List<IValueBinding<T>> _elements;
        private IClassFactory<T> _factory;


}
}
